/**
 * Copyright (C), 2015-2019, XXX有限公司
 * FileName: LambdaDemo
 * Author:   zhouheng
 * Date:     2019/4/6 10:19
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */

import exec.MyFunction;
import exec.MyFunction1;
import org.junit.Before;
import org.junit.Test;
import pojo.Employee;

import java.nio.file.OpenOption;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhouheng
 * @create 2019/4/6
 * @since 1.0.0
 */
public class LambdaDemo {

    public List<Employee> employees;

    @Before
    public void init(){
        employees = Arrays.asList(
            new Employee("1", "zhangsan", 5000d, 20, Employee.Status.FREE),
            new Employee("2", "lisi", 4000d, 40,Employee.Status.FREE),
            new Employee("3", "wangwu", 3000d, 30,Employee.Status.BUSY),
            new Employee("3", "wangwu", 3000d, 30,Employee.Status.FREE),
            new Employee("4", "zhaoliu", 6000d, 50,Employee.Status.BUSY));
    }

    @Test
    // 集合排序sort(lambda)
    public void TestLambda(){
        Collections.sort(employees, (x,y) -> {
            return x.getAge() - y.getAge();
        });

        for (Employee employee : employees){
            System.out.println(employee);
        }
    }

    @Test
    // 字符串大小写转换
    public void TestStr(){
        String str = "asdsadfa";
        String newStr = handleStr(str, x->x.toUpperCase());
        System.out.println(newStr);


        newStr = handleStr(str, x->x.length()+"");
        System.out.println(newStr);
    }

    @Test
    public void testTR(){
        Long sum = handleSum(3L,5L, (Object x, Object y) -> {
            return (Long)x + (Long)y;
        });

        System.out.println(sum);
    }


    public Long handleSum(Long l1, Long l2, MyFunction1 myFunction){
        Long sum = (Long) myFunction.handle(l1,l2);
        return sum;
    }

    public String handleStr(String str, MyFunction myFunction){
        String newStr = myFunction.handle(str);
        return newStr;
    }

    // java8 内置的4大核心函数接口
    // Comsumer<T> 消费型接口
    //      void accept(T t);
//    Supplier<T> 供给型接口
//            T get();
//    Function<T,R>  // 函数式接口
//        R apply(T t);

    @Test
    public void testComsumer(){
        filterConsumer(1000,(x)-> System.out.println(x));
    }

    public void filterConsumer(Integer t, Consumer<Integer> consumer){
        consumer.accept(t);
    }

    @Test
    public void testSupplier(){
        List<Integer> list = new ArrayList<>();

        list = getNumList(10, () -> {
           return (int)(Math.random() * 100);
        });

        for (Integer n : list){
            System.out.println(n);
        }

        System.out.println("jdk8之前");
        // jdk8之前
        List<Integer> list1 = new ArrayList<>();
        for(int i = 0; i < 10; i++){
            list1.add((int)(Math.random()*100));
        }

        for (Integer n : list1){
            System.out.println(n);
        }


    }
    public List<Integer> getNumList(int count, Supplier<Integer> supplier){
        List<Integer> newList = new ArrayList<>();
        for (int i= 0; i < count; i++){
            Integer n = supplier.get();
            newList.add(n);
        }

        return newList;
    }

    @Test
    public void testFunction(){
        String newStr = (String) getFunction("zhouheng", (Object x) ->{
            return x.toString().toUpperCase();
        });
        System.out.println(newStr);
    }

    public Object getFunction(String oldStr, Function function){
       return function.apply(oldStr);
    }

    //Predicate<T> 断言型接口：
    @Test
    public void test4(){
        List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
        List<String> strList = filterStr(list, (s) -> s.length() > 3);

        for (String str : strList) {
            System.out.println(str);
        }
    }

    //需求：将满足条件的字符串，放入集合中
    public List<String> filterStr(List<String> list, Predicate<String> pre){
        List<String> strList = new ArrayList<>();

        for (String str : list) {
            if(pre.test(str)){
                strList.add(str);
            }
        }

        return strList;
    }

    @Test
    public void testStream(){
        Stream<Employee> newList = employees.stream().filter((x)->{
            return x.getAge() < 30;
        });
        newList.forEach(new Consumer<Employee>(){
            @Override
            public void accept(Employee employee) {
                System.out.println(employee.toString());
            }
        });
    }

    @Test
    public void testStreamMap(){
        employees.stream().map((str) -> {
            return str.getName().toUpperCase();
        }).forEach(System.out::println);
    }

    @Test
    public void testStreamDist(){
        employees.stream().filter((x)-> x.getAge() < 40)
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    // sort() 自然排序Comparable
    // sort() 定制排序Comparator
    public void testStreamSort(){
        employees.stream().sorted((e1,e2)->{
            return e1.getAge().compareTo(e2.getAge());
        }).forEach(System.out::println);
    }

    @Test
    // 查找与匹配
    //      allMatch——检查是否匹配所有元素
    //		anyMatch——检查是否至少匹配一个元素
    //		noneMatch——检查是否没有匹配的元素
    //		findFirst——返回第一个元素
    //		findAny——返回当前流中的任意元素
    //		count——返回流中元素的总个数
    //		max——返回流中最大值
    //		min——返回流中最小值
    public void testStreamQuery(){
        boolean bol = employees.stream().anyMatch(x ->
            x.getStatus().equals(Employee.Status.BUSY));
        System.out.println(bol);
    }

    @Test
    public void testStreamFindFirst(){
        Optional<Employee> optionalEmployee = employees.stream()
                .filter(t->t.getStatus().equals(Employee.Status.BUSY))
                .findFirst();
        System.out.println(optionalEmployee.get());

        Optional<Employee> op2 = employees.parallelStream()
                .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();

        System.out.println(op2.get());
    }

    @Test
    public void test3(){
        long count = employees.stream()
                .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
                .count();

        System.out.println(count);

        Optional<Double> op = employees.stream()
                .map(Employee::getSalary)
                .max(Double::compare);

        System.out.println(op.get());

        Optional<Employee> op2 = employees.stream()
                .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));

        System.out.println(op2.get());
    }

    /*
    p——接收 Lambda ， 将元素转换成其他形式或提取信息。
    接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
    fl映射
    maatMap——接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流
	 */

    @Test
    public void testStreamFlatMap(){
       Stream<String> str = employees.stream().map(x->x.getName());
//       str.forEach(System.out::println);

        List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        strList.stream().map(t->t.toUpperCase());

        Stream<String> stream = strList.stream()
                .map(String::toUpperCase);

        stream.forEach(System.out::println);

        Stream<Stream<Character>> stream1 = strList.stream().map(LambdaDemo::filterCharacter);
        stream1.forEach((sm) -> {
            sm.forEach(System.out::println);
        });

        System.out.println("--------------------------------");
        Stream<Character> stream2 = strList.stream().flatMap(LambdaDemo::filterCharacter);
        stream2.forEach(System.out::println);
    }

    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }

        return list.stream();
    }

    // 归约模式 map-reduce模式
    @Test
    public void test5(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);

        int sum = list.stream().reduce(0,(x,y)->{return (x+y);});
        System.out.println(sum);
        System.out.println("----------------------");
        Double sumSalary = employees.stream().map(x->x.getSalary())
                .reduce(0d,(x,y)->{return x+y;});
        System.out.println(sumSalary);
    }

    // collect 搜集
    @Test
    public void testStreamCollect(){
       List<String> nameList = employees.stream().map(x-> x.getName()).collect(Collectors.toList());
       nameList.forEach(System.out::println);

        HashSet<String> hashSet = employees.stream()
                .map(x-> x.getName())
                .collect(Collectors.toCollection(HashSet::new));

        hashSet.stream().forEach(System.out::println);
    }

    // 最大值 最小值 平均数
    @Test
    public void testStreamMaxMinAvg(){
       System.out.println("-----------avg--------------");
       Double salaryAvg = employees.stream().collect(Collectors.averagingDouble(t->t.getSalary()));
       System.out.println(salaryAvg);
       System.out.println("-------------max-------------");
       Optional<Employee> max = employees.stream().collect(Collectors.maxBy((t1,t2)->{
           return Double.compare(t1.getSalary(),t2.getSalary());
       }));

        System.out.println(max.get().getSalary());

        System.out.println("--------------sum-----------");
        Double sumSalary = employees.stream().collect(Collectors.summingDouble(t-> {return t.getSalary();}));
        System.out.println(sumSalary);

        System.out.println("-----------min-----------------");
        Optional<Double> minSalary = employees.stream().map(t->t.getSalary()).collect(Collectors.minBy(Double::compare));
        System.out.println(minSalary.get());

        System.out.println("--------------------");
        DoubleSummaryStatistics dss =  employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getAverage());
    }

    @Test
    public void testOptional(){
        Optional<Employee> optionalEmployee = Optional.of(new Employee());

        System.out.println(optionalEmployee.get());
    }
    @Test
    public void testOptionalEmpty(){
        Optional<Employee> optionalEmployee = Optional.empty();

        System.out.println(optionalEmployee.get());
    }

    @Test
    public void testOptionalOfNullable(){
        Optional<Employee> optionalEmployee = Optional.ofNullable(null);

        if (optionalEmployee.isPresent()){
            System.out.println(optionalEmployee.get());
        }

    }

    @Test
    public void testOptionalOrElse(){
        Optional<Employee> optionalEmployee = Optional.ofNullable(null);
        Optional<String> strname = optionalEmployee.map(e->e.getName());
        System.out.println(strname.get());


    }

}